/********************************************************************
 *
 *      Filename: VectorMath.h
 *   Description: Math for 2-, 3-, and 4-dimensional vectors
 *        Author: [kb]ypp
 *    Created at: December 12, 2006
 *
 ********************************************************************/

#ifndef VECTORMATH_H
#define VECTORMATH_H

namespace math {

//! @brief 2-component vector
//!
template< typename T >
class Vec2 {
public:
    typedef T coord_type;
    
    coord_type x, y;
    
    Vec2() {}
    
    explicit Vec2( coord_type xx, coord_type yy )
        : x( xx ), y( yy ) {}
};

typedef Vec2< float > float2;
typedef Vec2< double > double2;

//! @brief 3-component vector
//!
template< typename T >
class Vec3 {
public:
    typedef T coord_type;
    
    coord_type x, y, z;
    
    Vec3() {}
    
    explicit Vec3( coord_type xx, coord_type yy, coord_type zz )
        : x( xx ), y( yy ), z( zz ) {}
};

typedef Vec3< float > float3;
typedef Vec3< double > double3;

//! @brief 4-component vector
//!
template< typename T >
class Vec4 {
public:
    typedef T coord_type;
    
    coord_type x, y, z, w;
    
    Vec4() {}
    
    explicit Vec4( coord_type xx, coord_type yy, coord_type zz, coord_type ww )
        : x( xx ), y( yy ), z( zz ), w( ww ) {}
};

typedef Vec4< float > float4;
typedef Vec4< double > double4;

//! @brief Assignment with addition
template< typename T >
Vec2< T > operator+=( Vec2< T > lhs, Vec2< T > rhs );

template< typename T >
Vec3< T > operator+=( Vec3< T > lhs, Vec3< T > rhs );

template< typename T >
Vec4< T > operator+=( Vec4< T > lhs, Vec4< T > rhs );

//! @brief Assignment with subtraction
template< typename T >
Vec2< T > operator-=( Vec2< T > lhs, Vec2< T > rhs );

template< typename T >
Vec3< T > operator-=( Vec3< T > lhs, Vec3< T > rhs );

template< typename T >
Vec4< T > operator-=( Vec4< T > lhs, Vec4< T > rhs );

//! @brief Assignment with multiplication to scalar
template< typename T >
Vec2< T > operator*=( Vec2< T > lhs, typename Vec2< T >::coord_type factor );

template< typename T >
Vec3< T > operator*=( Vec3< T > lhs, typename Vec3< T >::coord_type factor );

template< typename T >
Vec4< T > operator*=( Vec4< T > lhs, typename Vec4< T >::coord_type factor );

//! @brief Positive of a vector (unary '+')
template< typename T >
Vec2< T > operator+( Vec2< T > v );

template< typename T >
Vec3< T > operator+( Vec3< T > v );

template< typename T >
Vec4< T > operator+( Vec4< T > v );

//! @brief Negation of a vector (unary '-')
template< typename T >
Vec2< T > operator-( Vec2< T > v );

template< typename T >
Vec3< T > operator-( Vec3< T > v );

template< typename T >
Vec4< T > operator-( Vec4< T > v );

//! @brief Componentwise vector addition
template< typename T >
Vec2< T > operator+( Vec2< T > lhs, Vec2< T > rhs );

template< typename T >
Vec3< T > operator+( Vec3< T > lhs, Vec3< T > rhs );

template< typename T >
Vec4< T > operator+( Vec4< T > lhs, Vec4< T > rhs );

//! @brief Componentwise vector subtraction
template< typename T >
Vec2< T > operator-( Vec2< T > lhs, Vec2< T > rhs );

template< typename T >
Vec3< T > operator-( Vec3< T > lhs, Vec3< T > rhs );

template< typename T >
Vec4< T > operator-( Vec4< T > lhs, Vec4< T > rhs );

//! @brief The product of scalar and a vector
template< typename T >
Vec2< T > operator*( typename Vec2< T >::coord_type factor, Vec2< T > rhs );

template< typename T >
Vec3< T > operator*( typename Vec3< T >::coord_type factor, Vec3< T > rhs );

template< typename T >
Vec4< T > operator*( typename Vec4< T >::coord_type factor, Vec4< T > rhs );

//! @brief The product of a vector and scalar
template< typename T >
Vec2< T > operator*( Vec2< T > lhs, typename Vec2< T >::coord_type factor );

template< typename T >
Vec3< T > operator*( Vec3< T > lhs, typename Vec3< T >::coord_type factor );

template< typename T >
Vec4< T > operator*( Vec4< T > lhs, typename Vec4< T >::coord_type factor );

//! @brief Equality (with tolerance) check
template< typename T >
bool operator==( Vec2< T > lhs, Vec2< T > rhs );

template< typename T >
bool operator==( Vec3< T > lhs, Vec3< T > rhs );

template< typename T >
bool operator==( Vec4< T > lhs, Vec4< T > rhs );

//! @brief Non-equality (with tolerance) check
template< typename T >
bool operator!=( Vec2< T > lhs, Vec2< T > rhs );

template< typename T >
bool operator!=( Vec3< T > lhs, Vec3< T > rhs );

template< typename T >
bool operator!=( Vec4< T > lhs, Vec4< T > rhs );

//! @brief Vector normalization
template< typename T >
void normalize( Vec2< T > v );

template< typename T >
void normalize( Vec3< T > v );

template< typename T >
void normalize( Vec4< T > v );

//! @brief The length (in other words: norm, magnitude) of a vector
template< typename T >
typename Vec2< T >::coord_type length( Vec2< T > v );

template< typename T >
typename Vec3< T >::coord_type length( Vec3< T > v );

template< typename T >
typename Vec4< T >::coord_type length( Vec4< T > v );

//! @brief The squared length of a vector
template< typename T >
typename Vec2< T >::coord_type lengthSq( Vec2< T > v );

template< typename T >
typename Vec3< T >::coord_type lengthSq( Vec3< T > v );

template< typename T >
typename Vec4< T >::coord_type lengthSq( Vec4< T > v );

//! @brief The dot product (also known as scalar product or inner product)
template< typename T >
typename Vec2< T >::coord_type dot( Vec2< T > lhs, Vec2< T > rhs );

template< typename T >
typename Vec3< T >::coord_type dot( Vec3< T > lhs, Vec3< T > rhs );

template< typename T >
typename Vec3< T >::coord_type dot( Vec4< T > lhs, Vec4< T > rhs );

//! @brief The cross product (also known as vector product)
template< typename T >
Vec3< T > cross( Vec3< T > lhs, Vec3< T > rhs );

} // namespace math

#endif // VECTORMATH_H
